#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File  : LGB自定义损失函数.py
# @Author: Richard Chiming Xu
# @Date  : 2022/1/12
# @Desc  :
import pandas as pd
import numpy as np
from sklearn import datasets

from sklearn.utils import shuffle
from sklearn import metrics
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split
import lightgbm as lgb

# 画图
import matplotlib.pyplot as plt
# 参数搜索
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV, cross_val_score
from bayes_opt import BayesianOptimization

import json
import pickle
from tqdm import tqdm

import warnings

warnings.filterwarnings('ignore')

# 读取数据
data = pd.read_csv("https://cdn.coggle.club/kaggle-flight-delays/flights_10k.csv.zip")

# 提取有用的列
data = data[["MONTH", "DAY", "DAY_OF_WEEK", "AIRLINE", "FLIGHT_NUMBER", "DESTINATION_AIRPORT",
             "ORIGIN_AIRPORT", "AIR_TIME", "DEPARTURE_TIME", "DISTANCE", "ARRIVAL_DELAY"]]
data.dropna(inplace=True)

# 筛选出部分数据
data["ARRIVAL_DELAY"] = (data["ARRIVAL_DELAY"] > 10) * 1

# 进行编码
cols = ["AIRLINE", "FLIGHT_NUMBER", "DESTINATION_AIRPORT", "ORIGIN_AIRPORT"]
for item in cols:
    data[item] = data[item].astype("category").cat.codes + 1

# 划分训练集和测试集
train, test, y_train, y_test = train_test_split(data.drop(["ARRIVAL_DELAY"], axis=1), data["ARRIVAL_DELAY"],
                                                random_state=10, test_size=0.25)


def loglikelihood(preds, train_data):
    labels = train_data.get_label()
    preds = 1. / (1. + np.exp(-preds))
    grad = preds - labels
    hess = preds * (1. - preds)

    proba = preds[np.array(labels) == 1]
    if len(proba[proba < 0.1]) > 0:
        grad *= 2
    return grad, hess


def binary_error(preds, train_data):
    labels = train_data.get_label()
    preds = 1. / (1. + np.exp(-preds))
    return 'error', np.mean(labels != (preds > 0.8)), False


# callback中重修改模型参数
def reset_metrics(X_test, y_test):
    def callback(env):
        origin_lr = env.params['learning_rate']
        ############  无聊代码，存粹为了体验一下callback   ############
        proba = env.model.predict(X_test)

        # 学习率衰减
        env.params['learning_rate'] = origin_lr * 0.99**env.iteration
        ############  无聊代码，存粹为了体验一下callback   ############

    callback.before_iteration = True
    callback.order = 0
    return callback


lgb_train = lgb.Dataset(train, y_train, free_raw_data=False, silent=True)
lgb_val = lgb.Dataset(test, y_test)
lgb_params = {
    'learning_rate': 0.01,
    'max_depth': 5,
    'n_estimators': 1000,
    'num_leaves': 128,
    'subsample_for_bin': 1000,
    'refit_decay_rate': 0.1,
    'verbose': -1

}
clf = lgb.train(params=lgb_params, train_set=lgb_train, num_boost_round=200, valid_sets=lgb_val,
                fobj=loglikelihood, feval=binary_error)
